package com.tanhua.dubbo.server.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.dubbo.server.pojo.UserLike;
import com.tanhua.dubbo.server.vo.PageInfo;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service(version = "1.0.0")
public class UserLikeApiImpl implements UserLikeApi {

    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    //喜欢列表的reidsKey
    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";

    //不喜欢列表的reidsKey
    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    /**
     * 喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
        /*
            1.判断是否喜欢过了
            2.有,直接返回
                没有,保存该用户信息
            3.将喜欢的用户这一行为存入redis中的喜欢列表中,(就是将谁喜欢谁存入redis中)
                   喜欢列表的redisKey为USER_LIKE_
            4.查看该用户是否在不喜欢的列表中,如果在就将他删除

         */

        //1.判断是否喜欢过了
        boolean result = isLike(userId, likeUserId);
        if (result) {
            return false;
        }
        //2.没有,保存该用户信息
        UserLike saveUserLike = new UserLike();
        saveUserLike.setId(ObjectId.get());
        saveUserLike.setUserId(userId);
        saveUserLike.setLikeUserId(likeUserId);
        saveUserLike.setCreated(System.currentTimeMillis());
        mongoTemplate.save(saveUserLike);

        //3.将喜欢的用户这一行为存入redis中的喜欢列表中,(就是将谁喜欢谁存入redis中)
        //喜欢列表的redisKey为USER_LIKE_
        String likeRedisKey = getLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        //在redis中redisKey的后缀为登录者id ,hashKey为喜欢用户的id
        redisTemplate.opsForHash().put(likeRedisKey, hashKey, "1");

        //4.查看该用户是否在不喜欢的列表中,如果在就将他删除
        if (disLike(userId, likeUserId)) {
            //不喜欢列表有值就要删除
            String disLikeRedisKey = getDisLikeRedisKey(userId);
            redisTemplate.opsForHash().delete(disLikeRedisKey, hashKey);
        }

        return true;
    }


    /**
     * 不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {

        //1.查询是否已经不喜欢
        boolean result = disLike(userId, likeUserId);
        if (result) {
            return false;
        }
        //2.不是就删除MongoDB中该位用户的信息
        Query query = Query.query(Criteria.where("userId").is(userId).and("likeUserId").is(likeUserId));
        mongoTemplate.remove(query, UserLike.class);
        //3,将不喜欢存入redis中的不喜欢列表
        String disLikeRedisKey = getDisLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        redisTemplate.opsForHash().put(disLikeRedisKey, hashKey, "1");
        //4.查看该用户是否在喜欢的列表中,如果在就将他删除
        if (isLike(userId, likeUserId)) {
            String likeRedisKey = getLikeRedisKey(userId);
            redisTemplate.opsForHash().delete(likeRedisKey, hashKey);
        }
        return true;
    }

    /**
     * 是否相互喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        return this.isLike(userId, likeUserId)
                && this.isLike(likeUserId, userId);
    }

    /**
     * 查询喜欢列表
     * 返回的是我喜欢用户的id集
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryLikeList(Long userId) {
        String likeRedisKey = getLikeRedisKey(userId);
        Set<Object> keys = redisTemplate.opsForHash().keys(likeRedisKey);
        if (CollUtil.isEmpty(keys)) {
            return ListUtil.empty();
        }
        List<Long> keyList = new ArrayList<>();
        for (Object key : keys) {
            keyList.add(Convert.toLong(key));
        }
        return keyList;
    }

    /**
     * 查询不喜欢列表
     *
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryNotLikeList(Long userId) {
        String disLikeRedisKey = getDisLikeRedisKey(userId);
        Set<Object> keys = redisTemplate.opsForHash().keys(disLikeRedisKey);
        if (CollUtil.isEmpty(keys)) {
            return ListUtil.empty();
        }
        List<Long> keyList = new ArrayList<>();
        for (Object key : keys) {
            keyList.add(Convert.toLong(key));
        }
        return keyList;
    }

    /**
     * 相互喜欢的数量
     * 相互喜欢的本质为:我的喜欢列表的有"他"
     * 而他的喜欢列表也有我
     * (*这里可以查询MongoDB,也可查redis,但一般来说能查redis就查redis,因为redis比较快)
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryMutualLikeCount(Long userId) {
        /*
                1.首先查询redis中查询我的喜欢列表,查出我喜欢用户的id
                2.利用该些用户的 id查他们的喜欢列表,看看有没有我

         */
        List<Long> likeUserIdList = queryLikeList(userId);
        Long count = 0L;
        for (Long likeUserId : likeUserIdList) {
            String likeRedisKey = getLikeRedisKey(likeUserId);
            String hashKey = String.valueOf(userId);
            Boolean result = redisTemplate.opsForHash().hasKey(likeRedisKey, hashKey);
            if (result) {
                count++;
            }
        }
        return count;
    }

    /**
     * 喜欢数
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryLikeCount(Long userId) {
        //直接查询redis中我的喜欢列表
        String likeRedisKey = getLikeRedisKey(userId);
        Long count = redisTemplate.opsForHash().size(likeRedisKey);
        return count;
    }

    /**
     * 粉丝数
     *
     * @param userId
     * @return
     */
    @Override
    public Long queryFanCount(Long userId) {
        //由于redis中没有记录过别人是否喜欢过我,所以只能去MongoDB中查user_like
        Query query = Query.query(Criteria.where("likeUserId").is(userId));
        long count = mongoTemplate.count(query, UserLike.class);
        return count;
    }

    /**
     * 相互喜欢的数量
     *
     * @return
     */
    @Override
    public Long queryEachLikeCount(Long userId) {
        //先查询我喜欢的列表,然后在我喜欢的人范围内,查询喜欢我的人

        Query query = Query.query(Criteria.where("userId").is(userId));
        List<UserLike> userLikes = this.mongoTemplate.find(query, UserLike.class);

        //获得所有id
        Set<Long> ids = userLikes.stream().map(UserLike::getLikeUserId).collect(Collectors.toSet());

        Query queryCount = Query.query(Criteria.where("userId").in(ids).and("likeUserId").is(userId));

        return this.mongoTemplate.count(queryCount, UserLike.class);
    }

    /**
     * 相互喜欢列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryMutualLikeList(Long userId, Integer page, Integer pageSize) {
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        //查询我喜欢用户的id集
        List<Long> likeList = queryLikeList(userId);
        Query query = Query.query(Criteria.where("userId").in(likeList).and("likeUserId").is(userId)).with(pageRequest);
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        pageInfo.setRecords(userLikes);
        return pageInfo;
    }

    /**
     * 查询我喜欢的列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryLikeList(Long userId, Integer page, Integer pageSize) {
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        //1.建立分页条件
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        //2.查询我喜欢列表,得到我喜欢用户的id
        List<Long> likeUserIdList = queryLikeList(userId);
        Query query = Query.query(Criteria.where("likeUserId").in(likeUserIdList)).with(pageRequest);
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        pageInfo.setRecords(userLikes);
        return pageInfo;
    }

    /**
     * 查询粉丝列表
     *
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<UserLike> queryFanList(Long userId, Integer page, Integer pageSize) {
        PageInfo<UserLike> pageInfo = new PageInfo<>();
        pageInfo.setPageNum(page);
        pageInfo.setPageSize(pageSize);
        PageRequest pageRequest = PageRequest.of(page - 1, pageSize, Sort.by(Sort.Order.desc("created")));
        Query query = Query.query(Criteria.where("likeUserId").is(userId)).with(pageRequest);
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        pageInfo.setRecords(userLikes);
        return pageInfo;
    }

    /**
     * 获得喜欢列表的redisKey
     *
     * @param userId
     * @return
     */
    private String getLikeRedisKey(Long userId) {
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 获得不喜欢列表的redisKey
     *
     * @param userId
     * @return
     */
    private String getDisLikeRedisKey(Long userId) {
        return LIKE_REDIS_KEY_PREFIX + userId;
    }

    /**
     * 是否喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    public boolean isLike(Long userId, Long likeUserId) {
        String likeRedisKey = getLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        return redisTemplate.opsForHash().hasKey(likeRedisKey, hashKey);
    }


    /**
     * 是否不喜欢
     *
     * @param userId
     * @param likeUserId
     * @return
     */
    public boolean disLike(Long userId, Long likeUserId) {
        String disLikeRedisKey = getDisLikeRedisKey(userId);
        String hashKey = String.valueOf(likeUserId);
        return redisTemplate.opsForHash().hasKey(disLikeRedisKey, hashKey);
    }
}
